fix(ui): give every page a main landmark and mark the sidebars as navigation - #1587
Open
culfin wants to merge 2 commits into
Open
fix(ui): give every page a main landmark and mark the sidebars as navigation#1587culfin wants to merge 2 commits into
culfin wants to merge 2 commits into
Conversation
No page of the interface carries a `main` landmark — `grep` for `<main` or `role="main"` across `ui/src` and `ui/template` returns nothing. The sidebar is a plain `div` as well. Screen reader users navigate by landmarks. Without a `main`, there is no way to skip past the header and the sidebar to the content; every visit to every page starts by tabbing through the whole navigation again. WCAG 2.4.1 (Bypass Blocks) is the criterion, and a landmark is the least intrusive way to satisfy it. Both layouts that carry the sidebar are changed: the wrapper around `Outlet` becomes `main`, and the sidebar container becomes `nav`. Class names are untouched, so nothing moves. Not included, and worth a look separately: the layouts that do not use the sidebar (`Admin`, `Users/Settings`, `Legal`) still need one, and with two `nav` landmarks on a page — this one and the header — an `aria-label` on each would help. That needs a new i18n key, so it is left out of a change that is otherwise markup only. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Aug 24, 2026
The admin area has a layout of its own and sits directly under `pages/Layout`, so the two changes above did not reach it. Nineteen further routes — signing in, registering, recovering an account, the error pages — have no layout at all; they get a pathless one that is nothing but a `main`. `pages/Layout` itself would be the wrong place: it wraps the header, so a landmark there would put the navigation inside the content region and "skip to content" would land before it. Verified structurally — 88 paths before, the same 88 after, no page removed — and by building the front end and stepping through the affected routes: each renders inside exactly one `main` and draws its content. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No page of the interface carries a
mainlandmark, and the sidebars are plaindivs.Visible on this project's own instance
meta.answer.dev/questions, fetched with a Googlebot user agent:Same in the source:
Why it matters
Screen reader users navigate by landmarks. Without a
main, there is no way toskip past the header and the sidebar to the content — every visit to every page
starts by tabbing through the whole navigation again. That is WCAG 2.4.1
(Bypass Blocks), and a landmark is the least intrusive way to satisfy it.
The change
Every route now sits inside exactly one
main:SideNavLayout,SideNavLayoutWithoutFooterAdminPlainLayout(pathless)pages/Layoutwould have been the wrong place for a single landmark: it wrapsthe header, so
mainthere would put the navigation inside the content regionand "skip to content" would land before it.
The sidebar containers become
navin the same three files. Class names areuntouched, so nothing moves on screen.
Verified
layout nodes added.
/users/login,/users/register,/50xand an unknown path — each renders inside exactlyone
mainand draws its content.The router diff looks larger than it is. Read with
git diff -wit is 24added lines; everything else is one indentation level.
Deliberately not included
With two
navlandmarks on a page — this one and the header — anaria-labelon each would tell them apart. That needs a new i18n key across 45 language
files, which does not belong in a change that is otherwise markup only.
Supersedes #1589 and #1591, which were the same work split across three pull
requests.
🤖 Generated with Claude Code